"""
文件分类器

基于规则和AI的文件分类器实现。
"""

import asyncio
from typing import Dict, List, Any, Optional
import logging
import re

from src.core.di import Injectable, Inject
from .base import FileClassifier, FileInfo, ClassificationRule, FileCategory, FileType


@Injectable(scope="singleton")
class MediaFileClassifier(FileClassifier):
    """
    媒体文件分类器
    
    基于规则的媒体文件分类器，支持自定义分类规则。
    """
    
    def __init__(self,
                 config: Dict[str, Any] = Inject("config"),
                 logger: logging.Logger = Inject("logger")):
        self.config = config
        self.logger = logger
        
        # 分类配置
        self.classifier_config = config.get("classifier", {})
        self.default_confidence = self.classifier_config.get("default_confidence", 0.5)
        
        # 分类规则
        self.rules: List[ClassificationRule] = []
        
        # 初始化默认规则
        self._initialize_default_rules()
    
    def _initialize_default_rules(self) -> None:
        """初始化默认分类规则"""
        
        # AI素材规则
        ai_rule = ClassificationRule(
            name="AI Generated Content",
            description="识别AI生成的素材",
            category=FileCategory.AI_GENERATED,
            file_patterns=[
                "*ai*", "*generated*", "*synthetic*", "*artificial*",
                "*midjourney*", "*dalle*", "*stable*diffusion*"
            ],
            path_patterns=[
                "*/ai/*", "*/generated/*", "*/synthetic/*"
            ],
            priority=10,
            confidence_boost=0.3
        )
        self.add_rule(ai_rule)
        
        # 产品展示规则
        product_display_rule = ClassificationRule(
            name="Product Display",
            description="产品展示素材",
            category=FileCategory.PRODUCT_DISPLAY,
            file_patterns=[
                "*product*", "*display*", "*showcase*", "*demo*",
                "*feature*", "*detail*", "*close*up*"
            ],
            path_patterns=[
                "*/product/*", "*/display/*", "*/showcase/*", "*/demo/*"
            ],
            priority=8,
            confidence_boost=0.2
        )
        self.add_rule(product_display_rule)
        
        # 产品使用规则
        product_usage_rule = ClassificationRule(
            name="Product Usage",
            description="产品使用场景素材",
            category=FileCategory.PRODUCT_USAGE,
            file_patterns=[
                "*usage*", "*using*", "*application*", "*tutorial*",
                "*howto*", "*guide*", "*instruction*"
            ],
            path_patterns=[
                "*/usage/*", "*/tutorial/*", "*/guide/*", "*/howto/*"
            ],
            priority=8,
            confidence_boost=0.2
        )
        self.add_rule(product_usage_rule)
        
        # 模特试穿规则
        model_wearing_rule = ClassificationRule(
            name="Model Wearing",
            description="模特试穿素材",
            category=FileCategory.MODEL_WEARING,
            file_patterns=[
                "*model*", "*wearing*", "*fashion*", "*outfit*",
                "*style*", "*look*", "*try*on*"
            ],
            path_patterns=[
                "*/model/*", "*/fashion/*", "*/outfit/*", "*/style/*"
            ],
            priority=8,
            confidence_boost=0.2
        )
        self.add_rule(model_wearing_rule)
        
        # 背景素材规则
        background_rule = ClassificationRule(
            name="Background Material",
            description="背景素材",
            category=FileCategory.BACKGROUND,
            file_patterns=[
                "*background*", "*bg*", "*backdrop*", "*scene*",
                "*environment*", "*setting*"
            ],
            path_patterns=[
                "*/background/*", "*/bg/*", "*/backdrop/*", "*/scene/*"
            ],
            priority=6,
            confidence_boost=0.1
        )
        self.add_rule(background_rule)
        
        # 宣传素材规则
        promotional_rule = ClassificationRule(
            name="Promotional Material",
            description="宣传素材",
            category=FileCategory.PROMOTIONAL,
            file_patterns=[
                "*promo*", "*ad*", "*advertisement*", "*marketing*",
                "*campaign*", "*commercial*", "*brand*"
            ],
            path_patterns=[
                "*/promo/*", "*/ad/*", "*/marketing/*", "*/campaign/*"
            ],
            priority=7,
            confidence_boost=0.15
        )
        self.add_rule(promotional_rule)
    
    def add_rule(self, rule: ClassificationRule) -> None:
        """添加分类规则"""
        self.rules.append(rule)
        # 按优先级排序
        self.rules.sort(key=lambda r: r.priority, reverse=True)
    
    def get_rules(self) -> List[ClassificationRule]:
        """获取所有分类规则"""
        return self.rules.copy()
    
    async def classify(self, file_info: FileInfo) -> FileInfo:
        """分类文件"""
        self.logger.debug(f"分类文件: {file_info.name}")
        
        best_category = FileCategory.UNCLASSIFIED
        best_confidence = 0.0
        matched_rules = []
        
        # 应用所有规则
        for rule in self.rules:
            if rule.matches(file_info):
                matched_rules.append(rule)
                
                # 计算置信度
                confidence = self.default_confidence + rule.confidence_boost
                
                # 如果这个规则的置信度更高，更新分类
                if confidence > best_confidence:
                    best_confidence = confidence
                    best_category = rule.category
        
        # 更新文件信息
        file_info.category = best_category
        file_info.confidence = min(best_confidence, 1.0)  # 确保不超过1.0
        
        # 添加匹配的规则作为标签
        for rule in matched_rules:
            if rule.name not in file_info.tags:
                file_info.tags.append(rule.name)
        
        self.logger.debug(f"分类结果: {file_info.name} -> {best_category.value} (置信度: {best_confidence:.2f})")
        
        return file_info


@Injectable(scope="singleton")
class SmartFileClassifier(FileClassifier):
    """
    智能文件分类器

    结合规则分类和AI分析的智能分类器。
    """

    def __init__(self,
                 rule_classifier: MediaFileClassifier = Inject(MediaFileClassifier),
                 config: Dict[str, Any] = Inject("config"),
                 logger: logging.Logger = Inject("logger")):
        self.rule_classifier = rule_classifier
        self.config = config
        self.logger = logger

        # 智能分类配置
        self.smart_config = config.get("smart_classifier", {})
        self.enable_ai_classification = self.smart_config.get("enable_ai", False)
        self.ai_confidence_threshold = self.smart_config.get("ai_confidence_threshold", 0.7)
        self.combine_rule_and_ai = self.smart_config.get("combine_rule_and_ai", True)

    def add_rule(self, rule: ClassificationRule) -> None:
        """添加分类规则"""
        self.rule_classifier.add_rule(rule)

    def get_rules(self) -> List[ClassificationRule]:
        """获取所有分类规则"""
        return self.rule_classifier.get_rules()

    async def classify(self, file_info: FileInfo) -> FileInfo:
        """智能分类文件"""
        self.logger.debug(f"智能分类文件: {file_info.name}")

        # 1. 首先使用规则分类
        file_info = await self.rule_classifier.classify(file_info)
        rule_category = file_info.category
        rule_confidence = file_info.confidence

        # 2. 如果启用AI分类且文件是视频
        if (self.enable_ai_classification and
            file_info.file_type == FileType.VIDEO and
            rule_confidence < self.ai_confidence_threshold):

            try:
                ai_result = await self._classify_with_ai(file_info)

                if ai_result and ai_result.get('confidence', 0) > self.ai_confidence_threshold:
                    if self.combine_rule_and_ai:
                        # 结合规则和AI结果
                        file_info = self._combine_classifications(
                            file_info, rule_category, rule_confidence, ai_result
                        )
                    else:
                        # 使用AI结果覆盖规则结果
                        file_info.category = FileCategory(ai_result['category'])
                        file_info.confidence = ai_result['confidence']
                        file_info.tags.append("AI_Classified")

            except Exception as e:
                self.logger.warning(f"AI分类失败 {file_info.name}: {e}")

        # 3. 基于元数据的启发式分类
        file_info = await self._heuristic_classification(file_info)

        return file_info

    async def _classify_with_ai(self, file_info: FileInfo) -> Optional[Dict[str, Any]]:
        """使用AI分类文件"""
        try:
            # 这里可以集成AI分类服务
            # 例如：使用视频帧分析、内容识别等

            # 暂时返回模拟结果
            # 在实际实现中，这里会调用AI服务

            # 基于文件名和路径的简单AI模拟
            filename_lower = file_info.name.lower()
            path_lower = file_info.path.lower()

            ai_categories = {
                'product': FileCategory.PRODUCT_DISPLAY,
                'model': FileCategory.MODEL_WEARING,
                'demo': FileCategory.PRODUCT_USAGE,
                'ai': FileCategory.AI_GENERATED,
                'promo': FileCategory.PROMOTIONAL
            }

            for keyword, category in ai_categories.items():
                if keyword in filename_lower or keyword in path_lower:
                    return {
                        'category': category.value,
                        'confidence': 0.8,
                        'method': 'ai_simulation'
                    }

            return None

        except Exception as e:
            self.logger.error(f"AI分类失败: {e}")
            return None

    def _combine_classifications(self,
                               file_info: FileInfo,
                               rule_category: FileCategory,
                               rule_confidence: float,
                               ai_result: Dict[str, Any]) -> FileInfo:
        """结合规则和AI分类结果"""

        ai_category = FileCategory(ai_result['category'])
        ai_confidence = ai_result['confidence']

        # 如果两种方法得出相同结果，提高置信度
        if rule_category == ai_category:
            file_info.confidence = min(1.0, (rule_confidence + ai_confidence) / 2 + 0.2)
            file_info.tags.append("Rule_AI_Agreement")
        else:
            # 如果结果不同，选择置信度更高的
            if ai_confidence > rule_confidence:
                file_info.category = ai_category
                file_info.confidence = ai_confidence
                file_info.tags.append("AI_Override")
            else:
                # 保持规则分类结果
                file_info.tags.append("Rule_Override")

        return file_info

    async def _heuristic_classification(self, file_info: FileInfo) -> FileInfo:
        """基于元数据的启发式分类"""

        # 如果已经有高置信度分类，跳过
        if file_info.confidence > 0.8:
            return file_info

        # 基于文件大小的启发式
        if file_info.file_type == FileType.VIDEO:
            size_mb = file_info.size / (1024 * 1024)

            # 非常小的视频文件可能是预览或缩略图
            if size_mb < 1:
                file_info.tags.append("Small_File")
                if file_info.category == FileCategory.UNCLASSIFIED:
                    file_info.category = FileCategory.BACKGROUND
                    file_info.confidence = 0.3

            # 非常大的视频文件可能是高质量的产品展示
            elif size_mb > 100:
                file_info.tags.append("Large_File")
                if file_info.category == FileCategory.UNCLASSIFIED:
                    file_info.category = FileCategory.PRODUCT_DISPLAY
                    file_info.confidence = 0.4

        # 基于时长的启发式（如果有元数据）
        duration = file_info.metadata.get('duration', 0)
        if duration > 0:
            if duration < 5:  # 短视频
                file_info.tags.append("Short_Video")
            elif duration > 60:  # 长视频
                file_info.tags.append("Long_Video")
                if file_info.category == FileCategory.UNCLASSIFIED:
                    file_info.category = FileCategory.PRODUCT_USAGE
                    file_info.confidence = 0.3

        # 基于分辨率的启发式
        resolution = file_info.metadata.get('resolution', '')
        if resolution:
            if '4k' in resolution.lower() or '2160' in resolution:
                file_info.tags.append("4K_Video")
            elif 'hd' in resolution.lower() or '1080' in resolution:
                file_info.tags.append("HD_Video")

        return file_info

    async def batch_classify(self, files: List[FileInfo]) -> List[FileInfo]:
        """批量分类文件"""
        self.logger.info(f"批量分类 {len(files)} 个文件")

        # 并发分类
        semaphore = asyncio.Semaphore(10)  # 限制并发数

        async def classify_single(file_info: FileInfo) -> FileInfo:
            async with semaphore:
                return await self.classify(file_info)

        tasks = [classify_single(file_info) for file_info in files]
        classified_files = await asyncio.gather(*tasks, return_exceptions=True)

        # 处理异常
        results = []
        for i, result in enumerate(classified_files):
            if isinstance(result, Exception):
                self.logger.error(f"分类文件失败 {files[i].name}: {result}")
                files[i].processing_errors.append(f"分类失败: {result}")
                results.append(files[i])
            else:
                results.append(result)

        return results
